package software.lib.service;

import lsh.Lsh;
import lsh.LshHelper;
import lsh.LshPackage.Pair;
import org.omg.CORBA.ORB;
import org.omg.CORBA.ORBPackage.InvalidName;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;
import org.omg.CosNaming.NamingContextPackage.CannotProceed;
import org.omg.CosNaming.NamingContextPackage.NotFound;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * Created by Wang on 2017/4/28.
 */
@Service
@Transactional
public class LshCaller {
    /**
     * 选取LSH结果的范围
     */
    public static final int MAX_RANGE = 10;

    public final static String[] languageList = {"Afrikaans","Albanian","Arabic","Bengali","Bosnian","Bulgarian","Chinese","Croatian","Czech","Dutch","English","Finnish","French","German","Greek","Gujarati","Haitian","Hebrew","Hindi","Hungarian","Indonesian","Italian","Japanese","Javanese","Kannada","Korean","Latin","Macedonian","Malay","Marathi","Panjabi","Pashto","Polish","Portuguese","Romanian","Russian","Scottish","Gaelic","Serbian","Sinhala,","Sinhalese","Spanish","Swahili","Swedish","Tagalog","Tamil","Telugu","Thai","Turkish","Ukrainian","Urdu","Vietnamese","Welsh"};

    @Transactional(readOnly = true)
    public Map<String, Object> query(String title){
        Map<String, Object> result = new HashMap<String, Object>();
        result.put("query",title);

        Lsh lsh = getInstance();
        Pair[] idlist = lsh.candidate(title);
        result.put("lsh",idlist);

//        System.out.println(Arrays.toString(idlist));

        StringBuilder stringBuilder = new StringBuilder("(");
        Arrays.stream(idlist).mapToInt(x->x.id).limit(Math.min(idlist.length, MAX_RANGE)).forEach(id->stringBuilder.append(id).append(","));
        stringBuilder.setCharAt(stringBuilder.length()-1,')');
        String idStr = stringBuilder.toString();

        try {
            Connection connection = dataSource.getConnection();
            PreparedStatement ps1 = connection.prepareStatement(
                    "SELECT min(score),max(score),min(timespan),max(timespan),min(duration),max(duration)," +
                            "min(price_low),max(price_high),min(avg_resp_time),max(avg_resp_time),min(sale_effiency),max(sale_effiency) " +
                            "FROM gig ,`user` " +
                            "WHERE id=seller_id AND gig_id IN "+idStr);
            PreparedStatement ps2 = connection.prepareStatement("SELECT country,COUNT(*) as num FROM gig ,`user` " +
                    "WHERE id=seller_id AND LENGTH(country)>2 AND gig_id IN "+idStr+" GROUP BY country ORDER BY num DESC ");

            PreparedStatement ps3 = connection.prepareStatement("SELECT language FROM gig ,`user` " +
                    "WHERE id=seller_id AND LENGTH(language)>10 AND gig_id IN "+idStr);

            PreparedStatement ps4 = connection.prepareStatement("SELECT tags FROM gig ,`user` " +
                    "WHERE id=seller_id AND LENGTH(tags)>4 AND gig_id IN "+idStr);

//            PreparedStatement ps5 = connection.prepareStatement("SELECT title FROM gig " +
//                    "WHERE gig_id=?");

//            Arrays.stream(idlist).mapToInt(x->x.id).forEach(value -> {
//                try {
//                    ps5.setInt(1,value);
//                    ResultSet rs = ps5.executeQuery();
//                    if(rs.next()) {
//                        String tt = rs.getString("title");
//                        System.out.println(tt);
//                    }
//                } catch (SQLException e) {
//                    e.printStackTrace();
//                }
//            });

            ResultSet rs1 = ps1.executeQuery();
            //TODO 处理查询结果
            if(rs1.next()){
                result.put("score_min",rs1.getDouble(1));
                result.put("score_max",rs1.getDouble(2));
                result.put("timespan_min",rs1.getInt(3));
                result.put("timespan_max",rs1.getInt(4));
                result.put("duration_min",rs1.getInt(5));
                result.put("duration_max",rs1.getInt(6));

                result.put("price_min",rs1.getInt(7));
                result.put("price_max",rs1.getInt(8));
                result.put("avg_resp_time_min",rs1.getInt(9));
                result.put("avg_resp_time_max",rs1.getInt(10));
                result.put("sale_effiency_min",rs1.getDouble(11));
                result.put("sale_effiency_max",rs1.getDouble(12));
            }

            ArrayList<String> country = new ArrayList<>();
            ResultSet rs2 = ps2.executeQuery();
            while (rs2.next()){
                country.add(rs2.getString(1));
            }
            result.put("country",country);

            TreeMap<String,Integer> language = new TreeMap<>();
            ResultSet rs3 = ps3.executeQuery();
            while (rs3.next()){
                String langStr = rs3.getString(1);
                Arrays.stream(languageList).parallel().filter(s -> langStr.contains(s)).forEach(lang->language.put(lang,1+(int)org.apache.commons.lang.ObjectUtils.defaultIfNull(language.get(lang),0)) );
            }

            Set<String> languageSet = language.keySet();
            List<String> languagelist = Stream.generate(languageSet.iterator()::next).limit(languageSet.size())
                    .sorted(Comparator.comparingInt(language::get))
                    .collect(Collectors.toList());

            result.put("language",languagelist);

            TreeMap<String,Integer> tags = new TreeMap<>();
            ResultSet rs4 = ps4.executeQuery();
            while (rs4.next()){
                Stream.of(rs4.getString(1).split("\\|")).forEach(
                        tag->tags.put(tag,1+(int)org.apache.commons.lang.ObjectUtils.defaultIfNull(tags.get(tag),0))
                );
            }

            Set<String> tagSet = tags.keySet();
            List<String> taglist = Stream.generate(tagSet.iterator()::next).limit(tagSet.size())
                    .sorted(Comparator.comparingInt(tags::get))
                    .collect(Collectors.toList());
            result.put("tags",taglist);

//            return result;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static Lsh getInstance(){
        Lsh lsh = null;

        //创建一个ORB实例
        ORB orb = ORB.init(new String[]{"-ORBInitRef", "NameService=corbaloc::localhost:6666/NameService"}, null);

        // 获取根名称上下文
        org.omg.CORBA.Object objRef = null;
        try {
            objRef = orb.resolve_initial_references("NameService");
        } catch (InvalidName e) {
            e.printStackTrace();
        }
        NamingContextExt neRef = NamingContextExtHelper.narrow(objRef);

        String name = "lsh.Lsh";
        try {

            //通过ORB拿到了server实例化好的实现类
            lsh = LshHelper.narrow(neRef.resolve_str(name));
        } catch (NotFound e) {
            e.printStackTrace();
        } catch (CannotProceed e) {
            e.printStackTrace();
        } catch (org.omg.CosNaming.NamingContextPackage.InvalidName e) {
            e.printStackTrace();
        }
        return lsh;
    }

    public static void main(String[] args){
//        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//        applicationContext.start();
//        LshCaller caller = applicationContext.getBean(LshCaller.class);

        long startTime=System.currentTimeMillis();
        Lsh lsh = getInstance();
        Pair[] idList = lsh.candidate("I want to make a website use Java.");
        long endTime=System.currentTimeMillis();
        Arrays.stream(idList).forEach(pair->System.out.println(pair.id+"\t"+pair.nid+"\t"+pair.similarity));
//        System.out.println(Arrays.toString(idList));

        System.out.println("Time Spend "+(endTime-startTime));
    }

    @Autowired
    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
}
